{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dc49375d-0f01-4ece-bd42-5f2b8d308de7",
   "metadata": {},
   "source": [
    "# 相关依赖包的下载与导入  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "923d4b43",
   "metadata": {},
   "source": [
    "参考项目地址：  \n",
    "https://github.com/ResDream/MindTinyRAG   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "abef3da6-e8e9-447a-837d-804c16ac45e8",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple, https://pypi.ngc.nvidia.com\n",
      "Requirement already satisfied: torch in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 1)) (2.5.1)\n",
      "Requirement already satisfied: transformers==4.47.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 2)) (4.47.0)\n",
      "Requirement already satisfied: sentence_transformers in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 3)) (3.4.0)\n",
      "Requirement already satisfied: beautifulsoup4~=4.12.3 in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 4)) (4.12.3)\n",
      "Requirement already satisfied: PyPDF2~=3.0.1 in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 5)) (3.0.1)\n",
      "Requirement already satisfied: markdown~=3.7 in /tmp/JJK/.venv/lib/python3.11/site-packages (from -r LLM_with_RAG_requirements.txt (line 6)) (3.7)\n",
      "Collecting jieba (from -r LLM_with_RAG_requirements.txt (line 7))\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/c6/cb/18eeb235f833b726522d7ebed54f2278ce28ba9438e3135ab0278d9792a2/jieba-0.42.1.tar.gz (19.2 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m19.2/19.2 MB\u001b[0m \u001b[31m5.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25h  Installing build dependencies ... \u001b[?25ldone\n",
      "\u001b[?25h  Getting requirements to build wheel ... \u001b[?25ldone\n",
      "\u001b[?25h  Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n",
      "\u001b[?25hRequirement already satisfied: filelock in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (3.16.1)\n",
      "Requirement already satisfied: huggingface-hub<1.0,>=0.24.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (0.27.1)\n",
      "Requirement already satisfied: numpy>=1.17 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (2.2.1)\n",
      "Requirement already satisfied: packaging>=20.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (24.2)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (6.0.2)\n",
      "Requirement already satisfied: regex!=2019.12.17 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (2024.11.6)\n",
      "Requirement already satisfied: requests in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (2.32.3)\n",
      "Requirement already satisfied: tokenizers<0.22,>=0.21 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (0.21.0)\n",
      "Requirement already satisfied: safetensors>=0.4.1 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (0.5.2)\n",
      "Requirement already satisfied: tqdm>=4.27 in /tmp/JJK/.venv/lib/python3.11/site-packages (from transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (4.67.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (4.12.2)\n",
      "Requirement already satisfied: networkx in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (3.4.2)\n",
      "Requirement already satisfied: jinja2 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (3.1.5)\n",
      "Requirement already satisfied: fsspec in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (2024.12.0)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.4.127 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.127)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.4.127 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.127)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.4.127 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.127)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==9.1.0.70 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (9.1.0.70)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.4.5.8 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.5.8)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.2.1.3 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (11.2.1.3)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.5.147 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (10.3.5.147)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.6.1.9 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (11.6.1.9)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.3.1.170 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.3.1.170)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.21.5 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (2.21.5)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.4.127 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.127)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12==12.4.127 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (12.4.127)\n",
      "Requirement already satisfied: triton==3.1.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (3.1.0)\n",
      "Requirement already satisfied: sympy==1.13.1 in /tmp/JJK/.venv/lib/python3.11/site-packages (from torch->-r LLM_with_RAG_requirements.txt (line 1)) (1.13.1)\n",
      "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from sympy==1.13.1->torch->-r LLM_with_RAG_requirements.txt (line 1)) (1.3.0)\n",
      "Requirement already satisfied: scikit-learn in /tmp/JJK/.venv/lib/python3.11/site-packages (from sentence_transformers->-r LLM_with_RAG_requirements.txt (line 3)) (1.6.0)\n",
      "Requirement already satisfied: scipy in /tmp/JJK/.venv/lib/python3.11/site-packages (from sentence_transformers->-r LLM_with_RAG_requirements.txt (line 3)) (1.15.0)\n",
      "Requirement already satisfied: Pillow in /tmp/JJK/.venv/lib/python3.11/site-packages (from sentence_transformers->-r LLM_with_RAG_requirements.txt (line 3)) (11.1.0)\n",
      "Requirement already satisfied: soupsieve>1.2 in /tmp/JJK/.venv/lib/python3.11/site-packages (from beautifulsoup4~=4.12.3->-r LLM_with_RAG_requirements.txt (line 4)) (2.6)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from jinja2->torch->-r LLM_with_RAG_requirements.txt (line 1)) (2.1.5)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /tmp/JJK/.venv/lib/python3.11/site-packages (from requests->transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (3.4.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /tmp/JJK/.venv/lib/python3.11/site-packages (from requests->transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (3.10)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /tmp/JJK/.venv/lib/python3.11/site-packages (from requests->transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (2.3.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /tmp/JJK/.venv/lib/python3.11/site-packages (from requests->transformers==4.47.0->-r LLM_with_RAG_requirements.txt (line 2)) (2024.12.14)\n",
      "Requirement already satisfied: joblib>=1.2.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from scikit-learn->sentence_transformers->-r LLM_with_RAG_requirements.txt (line 3)) (1.4.2)\n",
      "Requirement already satisfied: threadpoolctl>=3.1.0 in /tmp/JJK/.venv/lib/python3.11/site-packages (from scikit-learn->sentence_transformers->-r LLM_with_RAG_requirements.txt (line 3)) (3.5.0)\n",
      "Building wheels for collected packages: jieba\n",
      "  Building wheel for jieba (pyproject.toml) ... \u001b[?25ldone\n",
      "\u001b[?25h  Created wheel for jieba: filename=jieba-0.42.1-py3-none-any.whl size=19314508 sha256=f308dcd3527114b1523cfd5db3e422e02778af2b3c3c58c788bc6ba26ddbc9ae\n",
      "  Stored in directory: /tmp/pip-ephem-wheel-cache-bpttgs3o/wheels/37/08/79/ea7c0d2ca823affa13f89586a5a9eff8dd6ad589640396e1b5\n",
      "Successfully built jieba\n",
      "Installing collected packages: jieba\n",
      "Successfully installed jieba-0.42.1\n"
     ]
    }
   ],
   "source": [
    "!pip install -r LLM_with_RAG_requirements.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "902c08bc-1eb6-4062-83f2-c6bae74c9ce1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import PyPDF2\n",
    "import markdown\n",
    "import json\n",
    "from bs4 import BeautifulSoup\n",
    "import re\n",
    "import os\n",
    "from copy import copy\n",
    "from typing import Dict, List, Optional, Tuple, Union\n",
    "import numpy as np\n",
    "from tqdm import tqdm\n",
    "from torch import tensor"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "120489f3",
   "metadata": {},
   "source": [
    "**jieba分词**  \n",
    "<pre>\n",
    "jieba分词是一款基于词典的中文分词工具，它可以将中文文本分割成词语。\n",
    "</pre>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "48c32f06",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Building prefix dict from the default dictionary ...\n",
      "Loading model from cache /tmp/jieba.cache\n",
      "Loading model cost 0.967 seconds.\n",
      "Prefix dict has been built successfully.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Hello', ',', ' ', 'world', '!', ' ', '今天', '我', '去', '看', '了', '电影', 'Avatar', '。', '\\n', ' ', '我', '觉得', '这部', '电影', '太棒了', '！']\n"
     ]
    }
   ],
   "source": [
    "# jieba分词\n",
    "import jieba\n",
    "\n",
    "# 示例文本\n",
    "text = \"Hello, world! 今天我去看了电影Avatar。\\n 我觉得这部电影太棒了！\"\n",
    "print(list(jieba.cut(text)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "4da7541f-66e0-4683-bb89-e1074a6dedac",
   "metadata": {},
   "outputs": [],
   "source": [
    "os.environ[\"HF_ENDPOINT\"] = \"https://hf-mirror.com\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06693aa6-5624-4b80-9021-8fb680c29713",
   "metadata": {},
   "source": [
    "# 读取文件与处理\n",
    "1. 读取文件：读取对应文件夹下所有文件。\n",
    "\n",
    "2. 提取内容：判断文件类型，设计提取内容方式，实现多种格式统一化处理。\n",
    "\n",
    "3. 分块：采用滑动窗口分块的逻辑分割长文本，确保段落间的语义连续性。"
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "id": "b6f8b680",
   "metadata": {},
   "source": [
    "![image.png](attachment:image.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "8d07c2da-9f7f-4f21-b68d-1508625a4ed8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(['我爱我的祖国\\n蛇',\n",
       "  '\\n蛇年大吉！新年快乐\\n',\n",
       "  '新年快乐\\nHello, world!',\n",
       "  'world! 今天我去看',\n",
       "  '去看了电影Avatar。\\n',\n",
       "  '。\\n 我觉得这部电影',\n",
       "  '这部电影太棒了！'],\n",
       " [['我', '爱', '我', '的', '祖国', '\\n', '蛇'],\n",
       "  ['\\n', '蛇', '年', '大吉', '！', '新年快乐', '\\n'],\n",
       "  ['新年快乐', '\\n', 'Hello', ',', ' ', 'world', '!'],\n",
       "  ['world', '!', ' ', '今天', '我', '去', '看'],\n",
       "  ['去', '看', '了', '电影', 'Avatar', '。', '\\n'],\n",
       "  ['。', '\\n', ' ', '我', '觉得', '这部', '电影'],\n",
       "  ['这部', '电影', '太棒了', '！']])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class ReadFiles:\n",
    "    \"\"\"\n",
    "    class to read files\n",
    "    \"\"\"\n",
    "\n",
    "    # 定义 可支持读取的文件的类型( 根据类型编写相关读取函数：read_xxx() )\n",
    "    SUPPORT_TYPES = ['.md', '.txt', '.pdf']\n",
    "\n",
    "    def __init__(self, path: str) -> None:\n",
    "        \"\"\"\n",
    "        path: 文件所在文件夹的路径\n",
    "        \"\"\"\n",
    "        self._path = path\n",
    "        self.file_list = self.get_files()  # 获取 可支持类型的 文件的路径列表\n",
    "    \n",
    "    @classmethod\n",
    "    def read_pdf(cls, file_path: str):\n",
    "        # 读取PDF文件\n",
    "        with open(file_path, 'rb') as file:\n",
    "            reader = PyPDF2.PdfReader(file)\n",
    "            text = \"\"\n",
    "            for page_num in range(len(reader.pages)):\n",
    "                text += reader.pages[page_num].extract_text()\n",
    "            return text\n",
    "\n",
    "    @classmethod\n",
    "    def read_markdown(cls, file_path: str):\n",
    "        # 读取Markdown文件\n",
    "        with open(file_path, 'r', encoding='utf-8') as file:\n",
    "            md_text = file.read()\n",
    "            html_text = markdown.markdown(md_text)\n",
    "            # 使用BeautifulSoup从HTML中提取纯文本\n",
    "            soup = BeautifulSoup(html_text, 'html.parser')\n",
    "            plain_text = soup.get_text()\n",
    "            # 使用正则表达式移除网址链接\n",
    "            text = re.sub(r'http\\S+', '', plain_text) \n",
    "            return text\n",
    "\n",
    "    @classmethod\n",
    "    def read_text(cls, file_path: str):\n",
    "        # 读取文本文件\n",
    "        with open(file_path, 'r', encoding='utf-8') as file:\n",
    "            return file.read()\n",
    "    \n",
    "    def get_files(self):\n",
    "        # args：dir_path，目标文件夹路径\n",
    "        file_list = []  # 存储文件路径的列表\n",
    "\n",
    "        # 遍历目标文件夹的所有文件（含子目录中的文件）\n",
    "        for filepath, dirnames, filenames in os.walk(self._path):\n",
    "            # os.walk 函数将递归遍历指定文件夹\n",
    "            for filename in filenames:\n",
    "                # 通过后缀名判断 当前文件的类型是否满足要求\n",
    "                for support_type in self.SUPPORT_TYPES:\n",
    "                    if filename.endswith(support_type):\n",
    "                        # 如果满足要求，将其绝对路径加入到结果列表\n",
    "                        file_list.append(os.path.join(filepath, filename))\n",
    "                        break\n",
    "                    \n",
    "        return file_list\n",
    "\n",
    "    def get_content(self, chunk_size: int = 500, stride_size: int = 100):\n",
    "        docs = []\n",
    "        # 读取文件内容\n",
    "        for file in self.file_list:\n",
    "            content = self.read_file_content(file)  # 读取文件内容\n",
    "            # 切分长文本为多个文本块\n",
    "            chunk_content, _ = self.get_chunk(content, chunk_size=chunk_size, stride_size=stride_size)\n",
    "            # 将每个块加入到文档列表\n",
    "            docs.extend(chunk_content)\n",
    "        \n",
    "        # 返回最后进行分块处理后的文档列表\n",
    "        return docs\n",
    "\n",
    "    @classmethod\n",
    "    def get_chunk(cls, text: str, chunk_size: int = 500, stride_size: int = 100):\n",
    "        \"\"\"\n",
    "        滑动窗口分块策略\n",
    "            text: 待分块文本\n",
    "            chunk_size: 单个块的大小（单个文本块的token数量，这里的token指jieba分词后的词语/单词）\n",
    "            stride_size: 窗口滑动步长\n",
    "        \"\"\"\n",
    "        assert chunk_size > stride_size, \"chunk_size must be greater than stride_size\"\n",
    "\n",
    "        chunk_text = []\n",
    "        chunk_text_token_version = []\n",
    "\n",
    "        # 去掉text的换行符为空格\n",
    "        # text = text.replace('\\n', ' ')\n",
    "        \n",
    "        # 切分为单词列表\n",
    "        words = list(jieba.cut(text))\n",
    "        # 计算单词列表的长度\n",
    "        words_len = len(words)\n",
    "\n",
    "        # 计算overlap\n",
    "        overlap = chunk_size - stride_size\n",
    "        chunk_text_token_version.append(words[:chunk_size])  # 第一个块\n",
    "\n",
    "        # 循环遍历，生成其它块\n",
    "        for i in range(chunk_size, words_len, stride_size):\n",
    "            # 计算当前块的起始位置\n",
    "            start = i - overlap\n",
    "            # 计算当前块的结束位置\n",
    "            end = start + chunk_size\n",
    "\n",
    "            # 加入到块列表\n",
    "            chunk_text_token_version.append(words[start:end])\n",
    "        \n",
    "        # 将token列表转换为文本列表\n",
    "        chunk_text = [''.join(token_list) for token_list in chunk_text_token_version]\n",
    "\n",
    "        return chunk_text, chunk_text_token_version\n",
    "\n",
    "    @classmethod\n",
    "    def read_file_content(cls, file_path: str):\n",
    "        # 根据文件扩展名选择读取方法\n",
    "        if file_path.endswith('.pdf'):\n",
    "            return cls.read_pdf(file_path)\n",
    "        elif file_path.endswith('.md'):\n",
    "            return cls.read_markdown(file_path)\n",
    "        elif file_path.endswith('.txt'):\n",
    "            return cls.read_text(file_path)\n",
    "        else:\n",
    "            raise ValueError(\"Unsupported file type\")\n",
    "\n",
    "ReadFiles.get_chunk(\"我爱我的祖国\\n蛇年大吉！新年快乐\\nHello, world! 今天我去看了电影Avatar。\\n 我觉得这部电影太棒了！\", 7, 5)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "9f89fac4-2c0f-4392-9204-7cedc9c2b505",
   "metadata": {},
   "outputs": [],
   "source": [
    "files_dir = './datas_tested'\n",
    "texts = ReadFiles(files_dir)\n",
    "texts_chunks = texts.get_content(chunk_size = 500, stride_size = 300)  # 获得data目录下的所有文件内容并分割"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "1d91a07b-ce42-4104-8fd7-5fea4f642694",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[' \\n 1 请撰写一份课程报告，至少包含如下内容要点：  \\n1． 运筹学的定义，其在世界和我国的发展历史。  \\n2． 简述线性规划问题及其数学模型， 举例说明 单纯形法 求解线性规划问题 的原理\\n和过程。  \\n3． 介绍线性规划对偶问题的基本性质， 举例说明 对偶单纯形法 求解线性规划问题\\n的原理和过程。  \\n4． 介绍运输问题及其数学模型， 举例说明 表上作业法求解运输问题的原理。  \\n5． 介绍目标规划问题及其数学模型， 举例说明图解法求解目标规划问题的原理和\\n过程。  \\n6． 介绍整数规划问题及其数学模型，举例说明分支定界法求解整数规划问题的原\\n理和过程。  \\n7． 简述图与网络的关系，举例说明 Dijkstra 算法求解最短路问题的原理和过程。  \\n8． 介绍网络图的概念和应用场景，举例说明网络图时间参数的计算方法。  \\n9． 简述风险型决策和不确定型决策的关系，举例说明 不确定型决策的悲观准则、\\n乐观准则、折中准则、等可能准则和遗憾 准则。  \\n10． 谈谈运筹学课程对人工智能专业学习的重要性 ，以及学习运筹学课程的更\\n多体会。  \\n目录 \\n1 运筹学概述  ................................ ................................ ................................ ................................ ................  3 \\n1.1运筹学定义  ................................ ................................ ................................ ................................ ..... 3 \\n1.2发展历史  ................................ ................................ ................................ ................................ .........  3 \\n2线性规划问题及其数学模型  ................................ ................................ ................................ .....................  4 \\n2.1模型建立  ................................ ................................ ................................ ................................ .........  4 \\n2.2单纯形法求解线性规划问题  ................................ ................................ ................................ .........  7 \\n3介绍线性规划对偶问题  ................................ ................................ ................................ ...........................  10 \\n3.1基本性质  ................................ ................................ ................................ ................................ ....... 10 \\n3.2对偶单纯形法求解线性规划问题  ................................ ................................ ...............................  13 \\n4运输问题及其数学模型  ................................ ................................ ................................ ...........................  15 \\n4.1运输问题数学模型  ................................ ................................ ................................ .......................  15 \\n',\n",
       " '................................ ................................ ................................ ................................ ................  3 \\n1.1运筹学定义  ................................ ................................ ................................ ................................ ..... 3 \\n1.2发展历史  ................................ ................................ ................................ ................................ .........  3 \\n2线性规划问题及其数学模型  ................................ ................................ ................................ .....................  4 \\n2.1模型建立  ................................ ................................ ................................ ................................ .........  4 \\n2.2单纯形法求解线性规划问题  ................................ ................................ ................................ .........  7 \\n3介绍线性规划对偶问题  ................................ ................................ ................................ ...........................  10 \\n3.1基本性质  ................................ ................................ ................................ ................................ ....... 10 \\n3.2对偶单纯形法求解线性规划问题  ................................ ................................ ...............................  13 \\n4运输问题及其数学模型  ................................ ................................ ................................ ...........................  15 \\n4.1运输问题数学模型  ................................ ................................ ................................ .......................  15 \\n4.2表上作业法求解运输问题的原理  ................................ ................................ ...............................  16 \\n5目标规划问题及其数学模型  ................................ ................................ ................................ ...................  20 \\n5.1 提出问题与模型建立  ................................ ................................ ................................ ..................  20 \\n5.2 图解法求解目标规划问题  ................................ ................................ ................................ ..........  22 \\n6整数规划问题及其数学模型  ................................ ................................ ................................ ...................  23 \\n6.1 整数规划问题  ................................ ................................ ................................ ..............................  23 \\n6.2 分支定界法求解整数规划问题  ................................ ................................ ................................ .. 24 \\n7图与网络  ................................ ................................ ................................ ................................ ...................  26 \\n7.1 图与网络的关系简述  ................................ ................................ ................................ ..................  26 \\n7.2 Dijkstra 算法求解最短路问题  ................................ ................................ ................................ . 27 \\n8网络图  ................................ ................................ ................................ ................................ .......................  29  \\n 2 8.1 网络图的概念和应用场景  ................................ ................................ ................................ ..........  29 \\n8.2 网络图时间参数的计算方法  ................................ ................................ ................................ ...... 30 \\n9风险型决策和不确定型决策  ................................ ................................ ................................ ...................  31 \\n9.1风险型决策和']"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "texts_chunks[:2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "ad55a3f5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " \n",
      " 1 请撰写一份课程报告，至少包含如下内容要点：  \n",
      "1． 运筹学的定义，其在世界和我国的发展历史。  \n",
      "2． 简述线性规划问题及其数学模型， 举例说明 单纯形法 求解线性规划问题 的原理\n",
      "和过程。  \n",
      "3． 介绍线性规划对偶问题的基本性质， 举例说明 对偶单纯形法 求解线性规划问题\n",
      "的原理和过程。  \n",
      "4． 介绍运输问题及其数学模型， 举例说明 表上作业法求解运输问题的原理。  \n",
      "5． 介绍目标规划问题及其数学模型， 举例说明图解法求解目标规划问题的原理和\n",
      "过程。  \n",
      "6． 介绍整数规划问题及其数学模型，举例说明分支定界法求解整数规划问题的原\n",
      "理和过程。  \n",
      "7． 简述图与网络的关系，举例说明 Dijkstra 算法求解最短路问题的原理和过程。  \n",
      "8． 介绍网络图的概念和应用场景，举例说明网络图时间参数的计算方法。  \n",
      "9． 简述风险型决策和不确定型决策的关系，举例说明 不确定型决策的悲观准则、\n",
      "乐观准则、折中准则、等可能准则和遗憾 准则。  \n",
      "10． 谈谈运筹学课程对人工智能专业学习的重要性 ，以及学习运筹学课程的更\n",
      "多体会。  \n",
      "目录 \n",
      "1 运筹学概述  ................................ ................................ ................................ ................................ ................  3 \n",
      "1.1运筹学定义  ................................ ................................ ................................ ................................ ..... 3 \n",
      "1.2发展历史  ................................ ................................ ................................ ................................ .........  3 \n",
      "2线性规划问题及其数学模型  ................................ ................................ ................................ .....................  4 \n",
      "2.1模型建立  ................................ ................................ ................................ ................................ .........  4 \n",
      "2.2单纯形法求解线性规划问题  ................................ ................................ ................................ .........  7 \n",
      "3介绍线性规划对偶问题  ................................ ................................ ................................ ...........................  10 \n",
      "3.1基本性质  ................................ ................................ ................................ ................................ ....... 10 \n",
      "3.2对偶单纯形法求解线性规划问题  ................................ ................................ ...............................  13 \n",
      "4运输问题及其数学模型  ................................ ................................ ................................ ...........................  15 \n",
      "4.1运输问题数学模型  ................................ ................................ ................................ .......................  15 \n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(texts_chunks[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "e9e552a3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "................................ ................................ ................................ ................................ ................  3 \n",
      "1.1运筹学定义  ................................ ................................ ................................ ................................ ..... 3 \n",
      "1.2发展历史  ................................ ................................ ................................ ................................ .........  3 \n",
      "2线性规划问题及其数学模型  ................................ ................................ ................................ .....................  4 \n",
      "2.1模型建立  ................................ ................................ ................................ ................................ .........  4 \n",
      "2.2单纯形法求解线性规划问题  ................................ ................................ ................................ .........  7 \n",
      "3介绍线性规划对偶问题  ................................ ................................ ................................ ...........................  10 \n",
      "3.1基本性质  ................................ ................................ ................................ ................................ ....... 10 \n",
      "3.2对偶单纯形法求解线性规划问题  ................................ ................................ ...............................  13 \n",
      "4运输问题及其数学模型  ................................ ................................ ................................ ...........................  15 \n",
      "4.1运输问题数学模型  ................................ ................................ ................................ .......................  15 \n",
      "4.2表上作业法求解运输问题的原理  ................................ ................................ ...............................  16 \n",
      "5目标规划问题及其数学模型  ................................ ................................ ................................ ...................  20 \n",
      "5.1 提出问题与模型建立  ................................ ................................ ................................ ..................  20 \n",
      "5.2 图解法求解目标规划问题  ................................ ................................ ................................ ..........  22 \n",
      "6整数规划问题及其数学模型  ................................ ................................ ................................ ...................  23 \n",
      "6.1 整数规划问题  ................................ ................................ ................................ ..............................  23 \n",
      "6.2 分支定界法求解整数规划问题  ................................ ................................ ................................ .. 24 \n",
      "7图与网络  ................................ ................................ ................................ ................................ ...................  26 \n",
      "7.1 图与网络的关系简述  ................................ ................................ ................................ ..................  26 \n",
      "7.2 Dijkstra 算法求解最短路问题  ................................ ................................ ................................ . 27 \n",
      "8网络图  ................................ ................................ ................................ ................................ .......................  29  \n",
      " 2 8.1 网络图的概念和应用场景  ................................ ................................ ................................ ..........  29 \n",
      "8.2 网络图时间参数的计算方法  ................................ ................................ ................................ ...... 30 \n",
      "9风险型决策和不确定型决策  ................................ ................................ ................................ ...................  31 \n",
      "9.1风险型决策和\n"
     ]
    }
   ],
   "source": [
    "print(texts_chunks[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c1d4441-f09e-4737-89df-fa146be74c30",
   "metadata": {},
   "source": [
    "# Embedding设计：嵌入模型、检索、SentenceTransformer"
   ]
  },
  {
   "attachments": {
    "image-2.png": {
     "image/png": "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"
    },
    "image.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "id": "73705b6c",
   "metadata": {},
   "source": [
    "1. 嵌入模型：将文本转为可被计算机识别和认识的向量表示形式  \n",
    "![image.png](attachment:image.png)   \n",
    "\n",
    "2. 检索：通过两个不同文本对应的向量之间的相似度来衡量文本之间的相关性，从而可以实现通过一个文本找到其它相似的文本，也即“检索”  \n",
    "余弦相似度通过计算两个向量之间的夹角的余弦值，来表示它们在向量空间中的相似性。余弦相似度的值范围在 [ − 1 , 1 ]之间。  \n",
    "![image-2.png](attachment:image-2.png)\n",
    "\n",
    "3. SentenceTransformers是一个用于句子、文本嵌入的组件，提供了简单易用的接口来生成高质量的文本嵌入。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "597af364-5034-4848-91ff-17d37ed8b4c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "class BaseEmbeddings:\n",
    "    \"\"\"\n",
    "    Base class for embeddings\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, path: str, is_api: bool) -> None:\n",
    "        \"\"\"\n",
    "        参数：\n",
    "            path: 一个字符串，表示嵌入模型的路径或资源位置\n",
    "           is_api: 一个布尔值，表示是否通过 API 接口获取嵌入向量\n",
    "        \"\"\"\n",
    "        self.path = path\n",
    "        self.is_api = is_api\n",
    "\n",
    "    def get_embedding(self, text: str, model: str) -> List[float]:\n",
    "        pass\n",
    "        raise NotImplementedError\n",
    "\n",
    "    @classmethod\n",
    "    def cosine_similarity(cls, vector1: List[float], vector2: List[float]) -> float:\n",
    "        \"\"\"\n",
    "        calculate cosine similarity between two vectors\n",
    "        \"\"\"\n",
    "        dot_product = np.dot(vector1, vector2)\n",
    "        magnitude = np.linalg.norm(vector1) * np.linalg.norm(vector2)\n",
    "        if not magnitude:\n",
    "            return 0\n",
    "        return dot_product / magnitude"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "100f7354-a02d-4522-8228-8c7d6255b96b",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ModelEmbedding(BaseEmbeddings):\n",
    "    \"\"\"\n",
    "    class for Model embeddings\n",
    "    \"\"\"\n",
    "    def __init__(self, path: str = 'BAAI/bge-base-zh-v1.5', is_api: bool = False) -> None:\n",
    "        super().__init__(path, is_api)\n",
    "        self._model = self.load_model(path)\n",
    "\n",
    "    def get_embedding(self, text: str):\n",
    "        sentence_embedding = self._model.encode([text], normalize_embeddings=True)\n",
    "        return sentence_embedding\n",
    "\n",
    "    def load_model(self, path: str):\n",
    "        from sentence_transformers import SentenceTransformer\n",
    "        model = SentenceTransformer(path)\n",
    "        return model\n",
    "\n",
    "    @classmethod\n",
    "    def cosine_similarity(cls, sentence_embedding_1, sentence_embedding_2):\n",
    "        \"\"\"\n",
    "        calculate similarity between two vectors\n",
    "        \"\"\"\n",
    "        similarity = sentence_embedding_1 @ sentence_embedding_2.T\n",
    "        return similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "c7bf62b0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "torch.cuda.is_available()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "41f060f5-9b2c-412c-8701-87adb26e2f2d",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n",
      "To disable this warning, you can either:\n",
      "\t- Avoid using `tokenizers` before the fork if possible\n",
      "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "SentenceTransformer(\n",
       "  (0): Transformer({'max_seq_length': 512, 'do_lower_case': True}) with Transformer model: BertModel \n",
       "  (1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': True, 'pooling_mode_mean_tokens': False, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})\n",
       "  (2): Normalize()\n",
       ")"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bge_base_model = r\"BAAI/bge-base-zh-v1.5\"\n",
    "embedding = ModelEmbedding(bge_base_model) #\"BAAI/bge-base-zh-v1.5\"\n",
    "embedding._model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eed529bd-fb9d-46bb-b2cd-fb76252c0899",
   "metadata": {},
   "source": [
    "# 知识库设计：存储、检索指定文本嵌入向量的“数据库”"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64da8ab3",
   "metadata": {},
   "source": [
    "在RAG架构设计中，知识库通常使用向量数据库搭建。  \n",
    "<pre>\n",
    "    向量数据库是一种专门用于存储、索引和检索高维向量数据的数据库系统，它通过高效的相似性搜索功能，能够在大量向量数据中快速找到与查询向量最相似的向量，加速了检索的速度\n",
    "</pre>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "4d8842f6-d3d5-4a31-bd9b-f4bd6e618cc0",
   "metadata": {},
   "outputs": [],
   "source": [
    "class VectorStore:\n",
    "    def __init__(self, document: List[str] = ['']) -> None:\n",
    "        self.document = document\n",
    "\n",
    "    def get_vector(self, EmbeddingModel: BaseEmbeddings):\n",
    "        \"\"\"将文档列表self.document转换为嵌入向量列表self.vectors\"\"\"\n",
    "        self.vectors = []\n",
    "        for doc in tqdm(self.document, desc=\"Calculating embeddings\"):\n",
    "            self.vectors.append(EmbeddingModel.get_embedding(doc))\n",
    "        return self.vectors\n",
    "\n",
    "    def persist(self, path: str = 'storage'):\n",
    "        \"\"\"\"将文档和嵌入向量持久化到指定路径path\"\"\"\n",
    "        if not os.path.exists(path):\n",
    "            os.makedirs(path)\n",
    "        doc_path = os.path.join(path, 'document.json')\n",
    "        with open(doc_path, 'w', encoding='utf-8') as f:\n",
    "            json.dump(self.document, f, ensure_ascii=False)\n",
    "        if self.vectors:\n",
    "            # 将 numpy.ndarray 转换为列表\n",
    "            vectors_list = [vector.tolist() for vector in self.vectors]\n",
    "            vec_path = os.path.join(path,'vectors.json')\n",
    "            with open(vec_path, 'w', encoding='utf-8') as f:\n",
    "                json.dump(vectors_list, f)\n",
    "\n",
    "    def load_vector(self, EmbeddingModel: BaseEmbeddings, path: str = 'storage'):\n",
    "        \"\"\"从指定路径path加载文档和嵌入向量\"\"\"\n",
    "        if not os.path.exists(path):\n",
    "            raise FileNotFoundError(f\"Path {path} does not exist.\")\n",
    "        \n",
    "        vec_path = os.path.join(path,'vectors.json')\n",
    "        with open(vec_path, 'r', encoding='utf-8') as f:\n",
    "            vectors_list = json.load(f)\n",
    "\n",
    "        doc_path = os.path.join(path, 'document.json')\n",
    "        with open(doc_path, 'r', encoding='utf-8') as f:\n",
    "            self.document = json.load(f)\n",
    "\n",
    "        # 查询 EmbeddingModel 的类别\n",
    "        if isinstance(EmbeddingModel, ModelEmbedding):\n",
    "            # 将列表重新变为 numpy.ndarray\n",
    "            self.vectors = [np.array(vector) for vector in vectors_list]\n",
    "        else:\n",
    "            self.vectors = vectors_list\n",
    "\n",
    "    def get_similarity(self, vector1, vector2, EmbeddingModel: BaseEmbeddings):\n",
    "        \"\"\"计算两个向量的余弦相似度\"\"\"\n",
    "        return EmbeddingModel.cosine_similarity(vector1, vector2)\n",
    "\n",
    "    def query(self, query: str, EmbeddingModel: BaseEmbeddings, k: int = 1):\n",
    "        \"\"\"\n",
    "        查询文档库中与查询字符串最相似的 k 个文档。\n",
    "\n",
    "        Args:\n",
    "            query (str): 查询字符串（查询文本）\n",
    "            EmbeddingModel (BaseEmbeddings): 用于计算向量的模型\n",
    "            k (int, optional): 返回的最相似的 k 个文档数量. Defaults to 1.\n",
    "\n",
    "        Returns:\n",
    "            List[str]: 最相似的 k 个文档\n",
    "        \n",
    "        \"\"\"\n",
    "        # 获取查询字符串的嵌入向量\n",
    "        query_vector = EmbeddingModel.get_embedding(query)\n",
    "\n",
    "        # 计算查询向量与数据库中每个向量的相似度\n",
    "        similarities = [self.get_similarity(query_vector, vector, EmbeddingModel) for vector in self.vectors]\n",
    "\n",
    "        # 将相似度、向量和文档存储在一个列表中\n",
    "        results = []\n",
    "        for similarity, vector, document in zip(similarities, self.vectors, self.document):\n",
    "            results.append({\n",
    "                'similarity': similarity,\n",
    "                'vector': vector,\n",
    "                'document': document\n",
    "            })\n",
    "        # 按相似度从高到低排序\n",
    "        results.sort(key=lambda x: x['similarity'], reverse=True)\n",
    "        # 获取最相似的 k 个文档\n",
    "        top_k_documents = [result['document'] for result in results[:k]]\n",
    "\n",
    "        return top_k_documents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "a8c27994-f794-4494-86e7-758170ab710c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Calculating embeddings: 100%|██████████| 30/30 [00:01<00:00, 29.08it/s]\n"
     ]
    }
   ],
   "source": [
    "vector = VectorStore(texts_chunks)\n",
    "vector.get_vector(EmbeddingModel=embedding)\n",
    "vector.persist(path='storage')  # 将向量和文档内容保存到storage目录下，下次再用就可以直接加载本地的数据库\n",
    "vector.load_vector(EmbeddingModel=embedding, path='./storage')  # 加载本地的数据库"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4274bbf9-dd8e-480f-8af6-6a29e9c9535a",
   "metadata": {},
   "source": [
    "# 大语言模型：对话模型、提示设计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "c183fe75-8fa1-4af9-93b3-b526e8555d84",
   "metadata": {},
   "outputs": [],
   "source": [
    "class BaseModel:\n",
    "    def __init__(self) -> None:\n",
    "        self.model_path = None\n",
    "\n",
    "    def chat(self, prompt: str, history: List[dict], content: str) -> str:\n",
    "        pass\n",
    "\n",
    "    def load_model(self, model_path: str):\n",
    "        pass"
   ]
  },
  {
   "attachments": {
    "image-2.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "id": "a972c564",
   "metadata": {},
   "source": [
    "![image-2.png](attachment:image-2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "3582e6bd-000c-4110-8f34-73232e1a8cf9",
   "metadata": {},
   "outputs": [],
   "source": [
    "PROMPT_TEMPLATE = dict(\n",
    "    RAG_PROMPT_TEMPALTE=\"\"\"使用以上下文来回答用户的问题。如果你不知道答案，请输出“我不知道”。总是使用中文回答。\n",
    "        问题: {question}\n",
    "        可参考的上下文：\n",
    "        ···\n",
    "        {context}\n",
    "        ···\n",
    "        如果给定的上下文无法让你做出回答，请回答“数据库中没有这个内容，我不知道”。\n",
    "        有用的回答:\"\"\",\n",
    "    My_PROMPT_TEMPALTE=\"\"\"先对上下文进行内容总结,再使用上下文来回答用户的问题。如果你不知道答案，请输出“我不知道”。总是使用中文回答。\n",
    "        问题: {question}\n",
    "        可参考的上下文：\n",
    "        ···\n",
    "        {context}\n",
    "        ···\n",
    "        如果给定的上下文无法让你做出回答，请回答“数据库中没有这个内容，我不知道”。\n",
    "        有用的回答:\"\"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "718f2e62-8814-495a-97d7-479853bd6cc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "class ModelChat(BaseModel):\n",
    "    def __init__(self) -> None:\n",
    "        super().__init__()\n",
    "\n",
    "    def chat(self, prompt: str, history: List = [], content: str = '', max_length: int = 512, **kwargs) -> str:\n",
    "        if self.model is None:\n",
    "            return 'None'\n",
    "        \n",
    "        prompt = PROMPT_TEMPLATE['RAG_PROMPT_TEMPALTE'].format(question=prompt, context=content)     \n",
    "       \n",
    "        response, history = self.model.chat(self.tokenizer, prompt, history, max_length=max_length, **kwargs)\n",
    "        return response\n",
    "\n",
    "    def load_model(self, model_path: str, **kwargs):\n",
    "        self.model_path = model_path\n",
    "        from transformers import AutoTokenizer, AutoModelForCausalLM\n",
    "        \n",
    "        print('loading tokenizer and model ......')\n",
    "        self.tokenizer = AutoTokenizer.from_pretrained(self.model_path, **kwargs)\n",
    "        self.model = AutoModelForCausalLM.from_pretrained(self.model_path, **kwargs)\n",
    "        \n",
    "        # 判断self.model是否有 定义 chat 函数\n",
    "        if hasattr(self.model, 'chat'):\n",
    "            print(\"loading sucessfully!\")\n",
    "        else:\n",
    "            print(f\"{self.model_path} has not 'chat' function!\")\n",
    "            self.tokenizer = self.model = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "e172f3b2-14ed-48d6-bf99-7f49ccabae37",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loading tokenizer and model ......\n",
      "loading sucessfully!\n"
     ]
    }
   ],
   "source": [
    "chat = ModelChat()\n",
    "# model_path = 'openbmb/MiniCPM-2B-dpo-bf16'    #'openbmb/MiniCPM3-4B'\n",
    "# chat.load_model(model_path, cache_dir = 'cache_for_LLM_ckpt', trust_remote_code=True)\n",
    "\n",
    "model_path = '../MiniCPM-2B-dpo-bf16'  \n",
    "chat.load_model(model_path, trust_remote_code=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b3f7f193",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MiniCPMForCausalLM(\n",
       "  (model): MiniCPMModel(\n",
       "    (embed_tokens): Embedding(122753, 2304)\n",
       "    (layers): ModuleList(\n",
       "      (0-39): 40 x MiniCPMDecoderLayer(\n",
       "        (self_attn): MiniCPMSdpaAttention(\n",
       "          (q_proj): Linear(in_features=2304, out_features=2304, bias=False)\n",
       "          (k_proj): Linear(in_features=2304, out_features=2304, bias=False)\n",
       "          (v_proj): Linear(in_features=2304, out_features=2304, bias=False)\n",
       "          (o_proj): Linear(in_features=2304, out_features=2304, bias=False)\n",
       "          (rotary_emb): MiniCPMRotaryEmbedding()\n",
       "        )\n",
       "        (mlp): MiniCPMMLP(\n",
       "          (gate_proj): Linear(in_features=2304, out_features=5760, bias=False)\n",
       "          (up_proj): Linear(in_features=2304, out_features=5760, bias=False)\n",
       "          (down_proj): Linear(in_features=5760, out_features=2304, bias=False)\n",
       "          (act_fn): SiLU()\n",
       "        )\n",
       "        (input_layernorm): MiniCPMRMSNorm()\n",
       "        (post_attention_layernorm): MiniCPMRMSNorm()\n",
       "      )\n",
       "    )\n",
       "    (norm): MiniCPMRMSNorm()\n",
       "  )\n",
       "  (lm_head): Linear(in_features=2304, out_features=122753, bias=False)\n",
       ")"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chat.model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "235e13a6-7c37-496e-b91e-6c33848c459d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n",
      "The `seen_tokens` attribute is deprecated and will be removed in v4.41. Use the `cache_position` model input instead.\n",
      "`get_max_cache()` is deprecated for all Cache classes. Use `get_max_cache_shape()` instead. Calling `get_max_cache()` will raise error from v4.48\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你好！很高兴认识你。我是一个语言模型，可以回答你的问题并提供相关信息。关于我自己，我是一组计算机程序，旨在帮助人们通过自然语言交流获取信息。我可以回答各种问题，包括但不限于：\n",
      "\n",
      "1. 你好！很高兴认识你。\n",
      "2. 我是一个语言模型，可以回答你的问题并提供相关信息。\n",
      "3. 关于我自己，我是一组计算机程序，旨在帮助人们通过自然语言交流获取信息。\n",
      "\n",
      "如果你有任何问题或需要帮助，请随时问我。\n"
     ]
    }
   ],
   "source": [
    "m = chat.chat('你好',[],'请简单介绍你自己。') # 测试例子\n",
    "print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f31417d4-2aa0-4183-a9e3-8532fb2b26f9",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['等）为生产、经营等实际应用提供更加优质的服务，这整个\\n过程其实非常复杂，从理论到实际应用，涉及计算机硬件性能、算法设计与实现等问\\n题，因为人力、物力、财力、时间等资源的有限，我们需要针对特定的问题进行逐步\\n的优化和完善。显然，提到“优化” ，自然和“运筹学”有着紧密的关系。  \\n在人工智能蓬勃发展的时代，运筹学课程和人工智能专业在发展和应用是互补\\n的、互相促进的，运筹学理论的研究、应用的普及离不开计算机、人工智能的发展，\\n我们回想一下运筹学的发展简史就会很清楚地看到，第一代、第二代、第三代电子计\\n算机的出现大大促进了运筹学在更多的实际实践中得到普及和应用。而运筹学的进一\\n步发展和完善，对人工智能的发展，如计算机性能、算法研究、实际应用等起到推动\\n和优化作用。  \\n  \\n 34 10.2学习运筹学课程的体会  \\n在课堂上的学习无疑是基础中的基础、且还不够全面，但 如今网络发达，各种学\\n习资源和资源获取渠道丰富，我们可以根据需要自主找资源学习，进而解决自己遇到\\n的问题。同时，也因为资源的庞杂，这要求我们要有是非辨别的能力，而课堂上老师\\n的教学、与同学老师的交流讨论以及自己课后的练习，都在潜移默化地让我们自己不\\n断地去学习。  \\n值得重点注意的是，在学习了运筹学后，我学习到了它的许多解决实际问题的\\n“工具” ，也许不能较深入地熟悉其底层的数学原理，但学会怎么用、何时用，特别对\\n人工智能专业的我来说，似乎更重要。运筹学可以作为如今人工智能的一门强大的\\n“工具” ，而工具的充分使用取决于我们动手使用它的积极性。所以，在今后需要使用\\n学习使用运筹学中更多的“工具”时，我应该积极地动手使用它，在实践中熟悉这门\\n工具，而不仅仅只是“纸上谈兵” 。  ']\n",
      "chat=<__main__.ModelChat object at 0x7f7be8d7aad0>\n",
      "人工智能的特点包括：\n",
      "\n",
      "1. 自主学习能力：人工智能系统可以通过学习、分析和处理数据，不断优化自身性能，提高解决问题的效率。\n",
      "2. 自适应性：人工智能系统可以根据环境的变化和任务的需求，自动调整自己的策略和行为，以适应不同的场景。\n",
      "3. 模拟人类智能：人工智能系统可以模拟人类的思维、判断和决策过程，实现类似人类的智能行为。\n",
      "4. 跨领域应用：人工智能技术可以应用于各个领域，如医疗、金融、交通、教育等，为各行各业提供智能化解决方案。\n",
      "5. 协同工作：人工智能系统可以与其他系统、设备或人类协同工作，共同完成任务，提高工作效率。\n",
      "6. 数据驱动：人工智能系统依赖于大量的数据，通过对数据的分析和处理，提取有用的信息，为决策提供支持。\n",
      "7. 持续进步：随着技术的不断发展和创新，人工智能系统可以不断更新和改进，实现更高的性能和更广泛的应用。\n",
      "\n",
      "根据给定的上下文，人工智能的特点并未直接提及，但我已经总结了人工智能的主要特点。\n"
     ]
    }
   ],
   "source": [
    "question = '人工智能的特点？'\n",
    "\n",
    "content = vector.query(question, EmbeddingModel=embedding, k=1)\n",
    "print(content)\n",
    "\n",
    "print(f'chat={chat}')\n",
    "print(chat.chat(question, [], content, max_length=1024)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "87796581",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "chat=<__main__.ModelChat object at 0x7f7be8d7aad0>\n",
      "人工智能（AI）的特点包括：\n",
      "1. 学习能力：AI系统可以通过学习数据和模式来改进其性能，使其能够适应新的任务和情境。\n",
      "2. 自主性：AI系统可以自主地做出决策，而无需人类干预。\n",
      "3. 自适应性：AI系统可以根据反馈和结果来调整其行为，以优化其性能。\n",
      "4. 推理能力：AI系统可以使用逻辑和推理来解决问题，并生成新的见解和洞见。\n",
      "5. 模拟能力：AI系统可以模拟人类行为和思维，以模拟人类决策的过程。\n",
      "6. 自动化：AI系统可以执行重复和繁琐的任务，从而释放人类的时间和精力。\n",
      "7. 协作能力：AI系统可以与人类合作，以共同完成任务和解决问题。\n",
      "8. 安全性：AI系统可以检测和防止恶意行为和攻击，以保护系统和数据的安全。\n",
      "9. 可靠性：AI系统可以基于可靠的数据和算法来做出决策，从而减少错误和偏差。\n",
      "10. 可解释性：AI系统可以提供有关其决策的解释和理由，以增加透明度和信任度。\n",
      "\n",
      "需要注意的是，AI的特点可能因不同的应用和情境而有所不同。\n"
     ]
    }
   ],
   "source": [
    "# 看看没有外部知识作为prompt，模型的回答如何\n",
    "question = '人工智能的特点？'\n",
    "content = '...'\n",
    "print(f'chat={chat}')\n",
    "print(chat.chat(question, [], content))  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "460dcb0e-e690-4d10-a1b4-168c6e13702c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[' \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n举行一次；  \\n50 年代末美国大约有半数的大公司在自己的经营管理中应用运筹\\n学； \\n1959年成立国际运筹学联合会  \\n20 世纪 60 年代至今  运筹学绪论进一步细分为各个分支 ,专业学术团体迅速增多 ,更多的期\\n刊创办,运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学\\n计划之中  \\n第三代电子数字计算机出现，运筹学得以应用在更复杂、更广泛的系\\n统 \\n \\n表3 运筹学在中国的发展  \\n时期 发展 \\n古代 运筹学思想在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等  \\n1956年 第一个运筹学小组在中国科学院力学研究所成立  \\n1957年 我国从“夫运筹帷幄之中 ,决胜千里之外” (见《史记·高祖本纪》 )这句\\n古语中摘取“运筹”二字 ,将 0.R.正式译作运筹学  \\n1958年 建立了运筹学研究室  \\n1960 年 在山东济南召开全国应用运筹学的经验交流和推广会议  \\n1980 年 4月 成立中国运筹学学会  \\n如今 我国各高等院校 ,特别是各经济管理类专业已普遍把运筹学作为一门专业\\n主干课程列入教学计划之中  \\n \\n无论从世界角度还是一个国家的角度，我们不难发现，', '\\n地使用人力、物力  \\n \\n《中国企业管理百科全书》\\n（1984年版） 运筹学应用分析、试验、量化的方法，对经济 管理系统中\\n人、财、物等有限资源进行统筹安排，为决策者提供有依据\\n的最优方案，以实现最有效的 管理 \\n在以上权威著作中，对运筹学的释义 多次提到了关键词“管理” ，并且和数学 相关\\n名词紧密相关。  \\n \\n1.2发展历史  \\n从世界专业角度来看，运筹学是在 20世纪30年代初发展起来的一门新兴学科 ，但\\n运筹学的思想在中国古代其实就被应用起来了。我们可以从运筹学在世界、中国的历\\n史关键时期了解其发展。  \\n表2 运筹学在世界的发展  \\n时期 背景、发展 \\n1938年-1942年 第二次世界大战期间，首先在英美两国发展起来  \\n“operation al research ”即O.R.（运筹学）术语确定  \\n“OR”成功地解决了许多重要作战问题  \\n1945年-20世纪50年\\n代初 “二战”后，进入 O.R.创建阶段  \\n1947年美国丹齐克提出了线性规划及其通用解法 ----单纯形法；  \\n1948年英国成立“运筹学俱乐部” ，美国麻省理工学院引入 O.R.课\\n程； \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n']\n",
      "chat=<__main__.ModelChat object at 0x7f7be8d7aad0>\n",
      "运筹学的发展可以追溯到20世纪30年代初，当时运筹学思想在世界范围内开始发展。在中国，运筹学思想在古代就已经被应用起来。运筹学的发展经历了以下几个阶段：\n",
      "\n",
      "1. 20世纪30年代初至50年代初期，运筹学得到了快速发展，特别是在第二次世界大战期间，运筹学得到了广泛应用，解决了许多重要作战问题。\n",
      "2. 1950年英国伯明翰大学正式开设运筹学课程，第一本运筹学杂志《运筹学季刊》在英国创刊；\n",
      "3. 1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；\n",
      "4. 1952年，第一个运筹学会——美国运筹学会成立，《运筹学学报》(Journal of ORSA) 出版；\n",
      "5. 20世纪50年代初至50年代末，运筹学得到了进一步的发展，电子计算机技术迅速发展，运筹学中的一些方法如单纯形法、动态规划方法等得以用来解决实际管理系统中的优化问题；\n",
      "6. 1956年到1959年，法国、印度、日本、荷兰、比利时等10个国家成立运筹学学会，同时6种运筹学刊物问世；\n",
      "7. 1957年在英国牛津大学召开了第一次国际运筹学会议，以后每三年举行一次；\n",
      "8. 50年代末，美国大约有半数的大公司在自己的经营管理中应用运筹学；\n",
      "9. 1959年成立国际运筹学联合会；\n",
      "10. 20世纪60年代至今，运筹学进一步细分为各个分支，专业学术团体迅速增多，更多的期刊创办，运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学计划之中。\n",
      "\n",
      "运筹学在中国的发展始于1956年，当时第一个运筹学小组在中国科学院力学研究所成立。1957年，中国从“夫运筹帷幄之中，决胜千里之外” (见《史记·高祖本纪》)这句古语中摘取“运筹”二字，将0.R.正式译作运筹学。1958年，建立了运筹学研究室，1960年在山东济南召开全国应用运筹学的经验交流和推广会议，1980年4月成立中国运筹学学会。如今，我国各高等院校，特别是各经济管理类专业已普遍把运筹学作为一门专业主干课程列入教学计划之中。\n"
     ]
    }
   ],
   "source": [
    "question = '简述运筹学的发展.'\n",
    "\n",
    "content = vector.query(question, EmbeddingModel=embedding, k=2)\n",
    "print(content)\n",
    "\n",
    "print(f'chat={chat}')\n",
    "print(chat.chat(question, [], content, max_length=2048))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d87d1dd1-1fd0-43aa-8f7f-0bc04ff27e31",
   "metadata": {},
   "source": [
    "# Rerank：优化检索结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "98a8684a-e423-4438-9efa-1e012fb76f83",
   "metadata": {},
   "outputs": [],
   "source": [
    "class BaseReranker:\n",
    "    \"\"\"\n",
    "    Base class for reranker\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, path: str) -> None:\n",
    "        self.path = path\n",
    "\n",
    "    def rerank(self, text: str, content: List[str], k: int) -> List[str]:\n",
    "        raise NotImplementedError"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "adc007b3-429a-467a-bdf8-2348d251456f",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyReranker(BaseReranker):\n",
    "    \"\"\"\n",
    "    class for MyReranker\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, path: str = 'BAAI/bge-reranker-base') -> None:\n",
    "        super().__init__(path)\n",
    "        self._model= self.load_model(path)\n",
    "\n",
    "    def rerank(self, text: str, content: List[str], k: int) -> List[str]:\n",
    "        query_embedding = self._model.encode(text, normalize_embeddings=True)\n",
    "        sentences_embedding = self._model.encode(sentences=content, normalize_embeddings=True)\n",
    "        similarity = query_embedding @ sentences_embedding.T\n",
    "        # 获取按相似度排序后的索引\n",
    "        ranked_indices = np.argsort(similarity)[::-1]  # 按相似度降序排序\n",
    "        # 选择前 k 个最相关的候选内容\n",
    "        top_k_sentences = [content[i] for i in ranked_indices[:k]]\n",
    "        return top_k_sentences\n",
    "\n",
    "    def load_model(self, path: str):\n",
    "        from sentence_transformers import SentenceTransformer\n",
    "        model = SentenceTransformer(path)\n",
    "        return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "881c516c-1ac3-43db-9164-284fce924d67",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "No sentence-transformers model found with name BAAI/bge-reranker-base. Creating a new one with mean pooling.\n",
      "Some weights of XLMRobertaModel were not initialized from the model checkpoint at BAAI/bge-reranker-base and are newly initialized: ['roberta.pooler.dense.bias', 'roberta.pooler.dense.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    }
   ],
   "source": [
    "# 创建RerankerModel\n",
    "rerank_model_path = r'BAAI/bge-reranker-base'\n",
    "reranker = MyReranker(rerank_model_path) #'BAAI/bge-reranker-base'\n",
    "\n",
    "vector = VectorStore()\n",
    "vector.load_vector(EmbeddingModel=embedding, path='./storage')  # 加载本地的数据库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "e03dd0ef-d80b-4d91-a527-d335fa8c3ad4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[' \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n举行一次；  \\n50 年代末美国大约有半数的大公司在自己的经营管理中应用运筹\\n学； \\n1959年成立国际运筹学联合会  \\n20 世纪 60 年代至今  运筹学绪论进一步细分为各个分支 ,专业学术团体迅速增多 ,更多的期\\n刊创办,运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学\\n计划之中  \\n第三代电子数字计算机出现，运筹学得以应用在更复杂、更广泛的系\\n统 \\n \\n表3 运筹学在中国的发展  \\n时期 发展 \\n古代 运筹学思想在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等  \\n1956年 第一个运筹学小组在中国科学院力学研究所成立  \\n1957年 我国从“夫运筹帷幄之中 ,决胜千里之外” (见《史记·高祖本纪》 )这句\\n古语中摘取“运筹”二字 ,将 0.R.正式译作运筹学  \\n1958年 建立了运筹学研究室  \\n1960 年 在山东济南召开全国应用运筹学的经验交流和推广会议  \\n1980 年 4月 成立中国运筹学学会  \\n如今 我国各高等院校 ,特别是各经济管理类专业已普遍把运筹学作为一门专业\\n主干课程列入教学计划之中  \\n \\n无论从世界角度还是一个国家的角度，我们不难发现，', '\\n地使用人力、物力  \\n \\n《中国企业管理百科全书》\\n（1984年版） 运筹学应用分析、试验、量化的方法，对经济 管理系统中\\n人、财、物等有限资源进行统筹安排，为决策者提供有依据\\n的最优方案，以实现最有效的 管理 \\n在以上权威著作中，对运筹学的释义 多次提到了关键词“管理” ，并且和数学 相关\\n名词紧密相关。  \\n \\n1.2发展历史  \\n从世界专业角度来看，运筹学是在 20世纪30年代初发展起来的一门新兴学科 ，但\\n运筹学的思想在中国古代其实就被应用起来了。我们可以从运筹学在世界、中国的历\\n史关键时期了解其发展。  \\n表2 运筹学在世界的发展  \\n时期 背景、发展 \\n1938年-1942年 第二次世界大战期间，首先在英美两国发展起来  \\n“operation al research ”即O.R.（运筹学）术语确定  \\n“OR”成功地解决了许多重要作战问题  \\n1945年-20世纪50年\\n代初 “二战”后，进入 O.R.创建阶段  \\n1947年美国丹齐克提出了线性规划及其通用解法 ----单纯形法；  \\n1948年英国成立“运筹学俱乐部” ，美国麻省理工学院引入 O.R.课\\n程； \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n', '应用在更复杂、更广泛的系\\n统 \\n \\n表3 运筹学在中国的发展  \\n时期 发展 \\n古代 运筹学思想在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等  \\n1956年 第一个运筹学小组在中国科学院力学研究所成立  \\n1957年 我国从“夫运筹帷幄之中 ,决胜千里之外” (见《史记·高祖本纪》 )这句\\n古语中摘取“运筹”二字 ,将 0.R.正式译作运筹学  \\n1958年 建立了运筹学研究室  \\n1960 年 在山东济南召开全国应用运筹学的经验交流和推广会议  \\n1980 年 4月 成立中国运筹学学会  \\n如今 我国各高等院校 ,特别是各经济管理类专业已普遍把运筹学作为一门专业\\n主干课程列入教学计划之中  \\n \\n无论从世界角度还是一个国家的角度，我们不难发现，运筹学的发展在实际 、理\\n论、交流分享等之间交叉、循环地向上进行。其实纵观其它学科的历史发展，都是从\\n实际应用需要诞生，经历理论发展、实际运用，不断地向前发展。这 启示我们关注 学\\n科理论学习的同时 也应多关注实践 。 \\n \\n2线性规划问题及其数学模型  \\n2.1模型建立  \\n 各行各业的生产和经营等的管理工作中，经常性的计划或规划中有着共同点：在\\n现有各项资源条件的限制下 ,如何确定方案 ,使预期目标达到最优；或为了达到预期目\\n标,确定使资源消耗为最少的方案。这也是线性规划问题的由来。 我们以图 1中的问题 \\n 5 为例，建立数学模型。  \\n \\n图1 线性规划问题示例 1 \\n 根据题意，我们建立该线性规划问题的数学模型如图 2，其中， Xi(i=1,2,3,4,5) \\n为决策变量， ①式为目标函数，②③④⑤为约束条件。 从图中的模型中我们可以看到\\n规划问题的数学模型的三个要素： (1)（决策）变量，是问题中要确定的未知量 , 它用\\n于表明规划中的用数量表示的方案、措施 ,可由决策者决定和控制 ']\n"
     ]
    }
   ],
   "source": [
    "# 从向量数据库中查询出最相似的 2 个文档（k = 3）\n",
    "content = vector.query(question, EmbeddingModel = embedding, k = 3)\n",
    "print(content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "31faa8d0-29b8-429c-86f7-764b408f70c2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[' \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n举行一次；  \\n50 年代末美国大约有半数的大公司在自己的经营管理中应用运筹\\n学； \\n1959年成立国际运筹学联合会  \\n20 世纪 60 年代至今  运筹学绪论进一步细分为各个分支 ,专业学术团体迅速增多 ,更多的期\\n刊创办,运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学\\n计划之中  \\n第三代电子数字计算机出现，运筹学得以应用在更复杂、更广泛的系\\n统 \\n \\n表3 运筹学在中国的发展  \\n时期 发展 \\n古代 运筹学思想在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等  \\n1956年 第一个运筹学小组在中国科学院力学研究所成立  \\n1957年 我国从“夫运筹帷幄之中 ,决胜千里之外” (见《史记·高祖本纪》 )这句\\n古语中摘取“运筹”二字 ,将 0.R.正式译作运筹学  \\n1958年 建立了运筹学研究室  \\n1960 年 在山东济南召开全国应用运筹学的经验交流和推广会议  \\n1980 年 4月 成立中国运筹学学会  \\n如今 我国各高等院校 ,特别是各经济管理类专业已普遍把运筹学作为一门专业\\n主干课程列入教学计划之中  \\n \\n无论从世界角度还是一个国家的角度，我们不难发现，', '\\n地使用人力、物力  \\n \\n《中国企业管理百科全书》\\n（1984年版） 运筹学应用分析、试验、量化的方法，对经济 管理系统中\\n人、财、物等有限资源进行统筹安排，为决策者提供有依据\\n的最优方案，以实现最有效的 管理 \\n在以上权威著作中，对运筹学的释义 多次提到了关键词“管理” ，并且和数学 相关\\n名词紧密相关。  \\n \\n1.2发展历史  \\n从世界专业角度来看，运筹学是在 20世纪30年代初发展起来的一门新兴学科 ，但\\n运筹学的思想在中国古代其实就被应用起来了。我们可以从运筹学在世界、中国的历\\n史关键时期了解其发展。  \\n表2 运筹学在世界的发展  \\n时期 背景、发展 \\n1938年-1942年 第二次世界大战期间，首先在英美两国发展起来  \\n“operation al research ”即O.R.（运筹学）术语确定  \\n“OR”成功地解决了许多重要作战问题  \\n1945年-20世纪50年\\n代初 “二战”后，进入 O.R.创建阶段  \\n1947年美国丹齐克提出了线性规划及其通用解法 ----单纯形法；  \\n1948年英国成立“运筹学俱乐部” ，美国麻省理工学院引入 O.R.课\\n程； \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n']\n"
     ]
    }
   ],
   "source": [
    "# 从一阶段查询结果中用Reranker再次筛选出最相似的2个文档\n",
    "rerank_content = reranker.rerank(question, content, k=2)\n",
    "print(rerank_content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "13fd324d-6345-40a4-9a58-4cf847b6a99f",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "运筹学的发展可以追溯到古代，当时运筹学思想已经在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等。1956年，第一个运筹学小组在中国科学院力学研究所成立，1957年，我国从古语中摘取“运筹”二字，将运筹学正式译作运筹学。1958年，建立了运筹学研究室，1960年，在山东济南召开全国应用运筹学的经验交流和推广会议，1980年4月，中国运筹学学会成立。如今，运筹学在中国得到了广泛应用，各高等院校特别是经济管理类专业普遍将运筹学作为一门专业主干课程列入教学计划之中。\n",
      "\n",
      "运筹学的发展经历了多个阶段，从20世纪50年代初到50年代末，运筹学得到了快速发展，电子计算机技术迅速发展，运筹学中一些方法如单纯形法、动态规划方法等得以用来解决实际管理系统中的优化问题。1956年到1959年，法国、印度、日本、荷兰、比利时等10个国家成立运筹学学会，同时6种运筹学刊物问世。1957年在英国牛津大学召开了第一次国际运筹学会议，以后每3年举行一次。50年代末，美国大约有半数的大公司在自己的经营管理中应用运筹学。1959年成立国际运筹学联合会。20世纪60年代至今，运筹学绪论进一步细分为各个分支，专业学术团体迅速增多，更多的期刊创办，运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学计划之中。第三代电子数字计算机出现，运筹学得以应用在更复杂、更广泛的系统中。\n"
     ]
    }
   ],
   "source": [
    "# 最后选择最相似的文档, 交给LLM作为可参考上下文\n",
    "best_content = rerank_content[0]\n",
    "print(chat.chat(question, [], best_content, max_length=1024))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "bcc6f767",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "' \\n1950年英国伯明翰大学正式开设运筹学课程， 第一本运筹学杂志 \\n 4 《运筹学季刊》于英国创刊 ； \\n1951年莫尔斯和金博尔合著的《运筹学方法》一书正式出版；  \\n1952 年，第一个运筹学会 ---美国运筹学会成立 ,《运筹学学报》\\n(Journal of ORSA) 出版 \\n \\n20 世纪50 年代初- \\n50 年代末 进入运筹学的成长阶段，电子计算机技术迅速发展 ,运筹学中一\\n些方法如单纯形法、动态规划方法等 ,得以用来解决实际管理系统中\\n的优化问题；  \\n1956 年到 1959 年，法国、印度、日本、荷兰、比利时等  10 个国\\n家成立运筹学学会 , 同时6 种运筹学刊物问世 ； \\n1957 年在英国牛津大学召开了第一次国际运筹学会议 ,以后每 3年\\n举行一次；  \\n50 年代末美国大约有半数的大公司在自己的经营管理中应用运筹\\n学； \\n1959年成立国际运筹学联合会  \\n20 世纪 60 年代至今  运筹学绪论进一步细分为各个分支 ,专业学术团体迅速增多 ,更多的期\\n刊创办,运筹学书籍大量出版，以及更多学校将运筹学课程纳入教学\\n计划之中  \\n第三代电子数字计算机出现，运筹学得以应用在更复杂、更广泛的系\\n统 \\n \\n表3 运筹学在中国的发展  \\n时期 发展 \\n古代 运筹学思想在不少文献中有记载，如田忌赛马、北宋丁渭修复皇宫等  \\n1956年 第一个运筹学小组在中国科学院力学研究所成立  \\n1957年 我国从“夫运筹帷幄之中 ,决胜千里之外” (见《史记·高祖本纪》 )这句\\n古语中摘取“运筹”二字 ,将 0.R.正式译作运筹学  \\n1958年 建立了运筹学研究室  \\n1960 年 在山东济南召开全国应用运筹学的经验交流和推广会议  \\n1980 年 4月 成立中国运筹学学会  \\n如今 我国各高等院校 ,特别是各经济管理类专业已普遍把运筹学作为一门专业\\n主干课程列入教学计划之中  \\n \\n无论从世界角度还是一个国家的角度，我们不难发现，'"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "best_content"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
